﻿#region 참조 네임스페이스

using Skying.Runtime.InteropServices;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;

#endregion

namespace Skying.Resources
{
	/// <summary>
	/// 아이콘 그룹 리소스를 구성하는 클래스로 <see cref="Skying.Resources.Resource"/>로부터 파생된다.
	/// </summary>
	public class IconGroupResource : Resource
	{
		#region 프로퍼티

		/// <summary>
		/// 아이콘 그룹 리소스 내의 아이콘과 아이디 쌍 목록을 가져온다.
		/// </summary>
		public List<KeyValuePair<int, Icon>> Values
		{
			get;
			private set;
		}

		#endregion

		#region 생성자/소멸자

		public IconGroupResource(IntPtr moduleHandle, IntPtr type, IntPtr name)
			: base(moduleHandle, type, name)
		{
			
		}

		#endregion

		#region 리소스

		/// <summary>
		/// 아이콘 그룹 리소스를 구성한다.
		/// </summary>
		public override void CombineResource()
		{
			int newHeaderSize = Marshal.SizeOf(typeof(NewHeader));
			int iconResDirSize = Marshal.SizeOf(typeof(IconResDir));
			int grpIconDirEntrySize = Marshal.SizeOf(typeof(GrpIconDirEntry));
			
			byte[] groupBuffer = this.LoadResourceBinary(base.TypeHandle, base._nameHandle);
			
			if (groupBuffer.Length > 0)
			{
				byte[] newHeaderBinary = groupBuffer.Subset(newHeaderSize);

				NewHeader newHeader = MarshalExtensions.ConvertBinaryToStructure<NewHeader>(newHeaderBinary);

				// NewHeader에 정의된 리소스 개수만큼 목록을 생성한다.
				this.Values = new List<KeyValuePair<int, Icon>>(newHeader.ResCount);

				// 초기 오프셋은 NewHeader 정보를 로드한 만큼부터 시작된다.
				int offset = newHeaderSize;

				for (int index = 0; index < newHeader.ResCount; index++)
				{
					byte[] grpIconDirEntryBinary = groupBuffer.Subset(offset, grpIconDirEntrySize);

					// 오프셋은 GrpIconDirEntry 정보를 로드한 만큼 증가한다.
					offset += grpIconDirEntrySize;

					GrpIconDirEntry grpIconDirEntry = MarshalExtensions.ConvertBinaryToStructure<GrpIconDirEntry>(grpIconDirEntryBinary);

					// 실제 아이콘 이미지의 바이너리를 가져온다.
					byte[] iconBinary = this.LoadResourceBinary(new IntPtr((int)ResourceTypes.RT_ICON), new IntPtr(grpIconDirEntry.Id));

					if (iconBinary != null && iconBinary.Length > 0)
					{
						using (MemoryStream stream = new MemoryStream())
						{
							using (BinaryWriter writer = new BinaryWriter(stream))
							{
								// NewHeader의 Reserved와 Type을 복사한다.
								writer.Write(newHeaderBinary, 0, 4);
								// Icon 리소스에 대한 이미지를 1개로 설정한다.
								writer.Write((short)1);

								// GrpIconDirEntry 구조체에서 Id 프로퍼티(ushort)를 제외한 나머지 정보를 복사한다.(실제로 복사되는 데이터는 IconResDir 구조체와 동일하다.)
								writer.Write(grpIconDirEntryBinary, 0, grpIconDirEntrySize - sizeof(ushort));

								// NewHeader와 IconResDir의 크기의 합을 설정한다.(유효성 점검 용도로 추정된다.)
								writer.Write(newHeaderSize + iconResDirSize);

								// 아이콘 이미지 바이너리를 복사한다.
								writer.Write(iconBinary);

								stream.Seek(0, SeekOrigin.Begin);

								this.Values.Add(new KeyValuePair<int, Icon>((int)grpIconDirEntry.Id, new Icon(stream)));
							}
						}
					}
				}
			}
		}

		#endregion
	}
}